use crate::{bootstrap::AppState, router::resp::RespVO};
use axum::extract::{Path, Query};
use axum::http::{Response, StatusCode};
use axum::{body::Body, extract::State, response::IntoResponse, Json};
use serde::{Deserialize, Serialize};
use serde_json::json;
use sky_pojo::vo::PageResult;

use crate::middleware::jwt::admin::Claims;
use crate::service;
use sky_common::open_api::EMPLOYEE_TAG;
use sky_common::utils;
use sky_pojo::dto::employee::{
    EmployeeDTO, EmployeeLoginDtO, EmployeePageQueryDTO, EmployeePassDTO, EmployeeStatusDTO,
};
use sky_pojo::vo::employee::{EmployeeLoginVo, EmployeeVO};

#[utoipa::path(method(post), path = "/login", tag = EMPLOYEE_TAG )]
pub async fn login(
    State(state): State<AppState>,
    Json(employee_dto): Json<EmployeeLoginDtO>,
) -> Response<Body> {
    tracing::info!("员工登录：{:?}", employee_dto);
    let result = service::employee::login(
        state.db_pool,
        EmployeeLoginDtO {
            username: employee_dto.username,
            password: utils::md5_hash(&employee_dto.password),
        },
    )
    .await;

    match result {
        Ok(emp) => {
            let token = Claims::new(Claims {
                id: emp.id,
                name: emp.name.clone(),
                username: emp.username.clone(),
                exp: None,
                sub: emp.create_user,
            })
            .unwrap();
            let _vo = EmployeeLoginVo {
                id: emp.id,
                user_name: emp.username,
                name: emp.name,
                token,
            };

            return RespVO::<EmployeeLoginVo>::success("登录成功!".to_owned(), Some(_vo))
                .into_response();
        }

        Err(msg) => RespVO::<()>::error_without_data(msg).into_response(),
    }
}

// Java 版本的 save
#[utoipa::path(method(post),
             path = "", tag = EMPLOYEE_TAG,
    security(
        ("Authorization" = [])
    )
)]
pub async fn add_employee(
    _claim: Claims,
    State(_state): State<AppState>,
    Json(employee_dto): Json<EmployeeDTO>,
) -> Response<Body> {
    tracing::info!("员工添加: {:?}", employee_dto);

    match service::employee::add_employee(
        _state.db_pool,
        EmployeeDTO {
            password: utils::md5_hash(&employee_dto.password),
            ..employee_dto
        },
        _claim.id,
    )
    .await
    {
        Ok(e) => RespVO::<serde_json::Value>::from_result(
            Some(1),
            Some("员工创建成功".to_owned()),
            Some(json!({ "id": e.id })),
        )
        .into_response(),
        Err(err) => RespVO::<()>::error_without_data(err).into_response(),
    }
}

#[utoipa::path(method(get),
    path = "/page", tag = EMPLOYEE_TAG,
    security(
        ("Authorization" = [])
    ),
    params(
        EmployeePageQueryDTO
    )
)]
pub async fn page_query(
    _claim: Claims,
    State(_state): State<AppState>,
    Query(query): Query<EmployeePageQueryDTO>,
) -> Response<Body> {
    match service::employee::page_query(_state.db_pool, query).await {
        Ok(data) => RespVO::<PageResult<EmployeeVO>>::from_result(
            Some(StatusCode::OK.as_u16()),
            None,
            Some(data),
        )
        .into_response(),
        Err(err) => RespVO::<()>::error_without_data(err).into_response(),
    }
}

pub async fn find_by_id(
    _claim: Claims,
    State(_state): State<AppState>,
    Path(user_id): Path<i64>,
) -> Response<Body> {
    match service::employee::find_by_id(_state.db_pool, user_id).await {
        Ok(emp) => RespVO::<EmployeeVO>::success("成功".to_owned(), Some(emp)).into_response(),
        Err(err) => RespVO::<()>::error_without_data(err).into_response(),
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct EDQuery {
    pub id: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct EDPath {
    pub status: String,
}

pub async fn enable_disable(
    State(_state): State<AppState>,
    _claim: Claims,
    Query(qdto): Query<EDQuery>,
    Path(pdto): Path<EDPath>,
) -> Response<Body> {
    let id = match qdto.id.parse::<i64>() {
        Ok(id) => id,
        Err(err) => {
            tracing::error!("{}", err.to_string());
            return RespVO::<()>::error_without_data(err.to_string()).into_response();
        }
    };

    let status = match pdto.status.parse::<i32>() {
        Ok(status) => status,
        Err(err) => {
            tracing::error!("{}", err.to_string());
            return RespVO::<()>::error_without_data(err.to_string()).into_response();
        }
    };

    let employee_dto = EmployeeStatusDTO { id, status };
    match service::employee::enable_disable(_state.db_pool, employee_dto, _claim.id).await {
        Ok(emp) => RespVO::<EmployeeVO>::success("成功".to_owned(), Some(emp)).into_response(),
        Err(err) => RespVO::<()>::error_without_data(err).into_response(),
    }
}

pub async fn update_employee(
    _claim: Claims,
    State(_state): State<AppState>,
    Json(employee_dto): Json<EmployeeDTO>,
) -> Response<Body> {
    match service::employee::update_employee(_state.db_pool, employee_dto, _claim.id).await {
        Ok(emp) => RespVO::<EmployeeVO>::success("成功".to_owned(), Some(emp)).into_response(),
        Err(err) => RespVO::<()>::error_without_data(err).into_response(),
    }
}

pub async fn edit_password(
    _claim: Claims,
    State(_state): State<AppState>,
    Json(pass_dto): Json<EmployeePassDTO>,
) -> Response<Body> {
    match service::employee::modify_password(_state.db_pool, pass_dto, _claim.id).await {
        Ok(emp) => RespVO::<EmployeeVO>::success("成功".to_owned(), Some(emp)).into_response(),
        Err(err) => RespVO::<()>::error_without_data(err).into_response(),
    }
}

// 测试内容
// #[utoipa::path( method(post, get), path = "/test", tag = EMPLOYEE_TAG )]
// pub async fn get_cuerrent_info(State(state): State<AppState>) -> Response<Body> {
// RespVO::<()>::error_without_data(format!("token_test")).into_response()
// }

// #[utoipa::path(method(post),
//  path = "/verify", tag = EMPLOYEE_TAG,
// security(
// ("Authorization" = [])
// )
// )]
// pub async fn verify(claims: Claims, State(_state): State<AppState>) -> Response<Body> {
// tracing::info!("员工验证测试：{:?}", claims.id);
//
// RespVO::<Claims>::success("".to_string(), Some(claims)).into_response()
// }
